package com.gitee.chili.leisure.template;

import com.gitee.chili.leisure.Tools;
import com.gitee.chili.leisure.core.GameTemplate;
import com.gitee.chili.leisure.game.MahjongPlayer;
import com.gitee.chili.leisure.game.Player;
import com.gitee.chili.leisure.game.RoomDetail;
import com.gitee.chili.leisure.util.Utils;
import com.gitee.chili.leisure.util.functional.Function;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.atomic.LongAdder;

/**
 * MahjongTemplate
 *
 * @author week solider
 * @since 2020.09.17
 */
@Component
public class MahjongTemplate implements GameTemplate {

    @Override
    public void shuffle(int count, List<Integer> cards, RoomDetail roomDetail) {
        Function.foreach(count, i -> Collections.shuffle(cards));
        roomDetail.setCards(cards);
    }

    @Override
    public void deal(List<Integer> cards, List<? extends Player> players, RoomDetail roomDetail) {

        // 剩下的牌的数量
        int reserveCardNum = cards.size() - (13 * players.size());

        // 发牌座位
        LongAdder seat = new LongAdder();

        // 发牌的总数
        int dealCount = cards.size() - reserveCardNum;

        // 发牌
        Function.foreach(dealCount, idx -> {
            Player player = players.get(seat.intValue() % players.size());
            if (drawTurn(player))
                seat.increment();
            player.draw(cards.get(idx));
        });

        // 庄家多一张
        Utils.accept(players, Player::isBanker, player -> player.draw(cards.get(dealCount)));

        // 当前牌的位置
        roomDetail.setRestCardsNum(reserveCardNum)
                .setDrawCardPosition(dealCount);
    }

    @Override
    public void sort(List<? extends Player> players) {
        int size = players.size();
        // 由于牌的生成本就是按自然数排序,  所以这里只需要正常排序就行
        Function.foreach(size, i -> Collections.sort(players.get(i % size).getHandsCards()));
    }

    @Override
    public void election(List<? extends Player> players) {
        int size = players.size();

        // 掷骰子
        Function.foreach(size, seat -> {
            MahjongPlayer mahjongPlayer = (MahjongPlayer) players.get(seat % size);
            mahjongPlayer.setDiceFirst(Tools.shaker());
            mahjongPlayer.setDiceSecond(Tools.shaker());
        });

        // 统计玩家骰子点数
        // 键为玩家掷骰子总点数  值为座位号  (为什么键一定是骰子总点数?)
        // 方便计算，即使有相同的点数  我们也能保证庄的产生
        // 且可以通过 Map 键值对特性获取到玩家座位号 (为了快速定位, 所以键必须是骰子点数)
        Map<Integer, Integer> seatDiceSum = new HashMap<>();
        for (Player player : players) {
            MahjongPlayer mp = (MahjongPlayer) player;
            int diceSum = mp.getDiceFirst() + mp.getDiceSecond();
            seatDiceSum.put(diceSum, mp.getPosition());
        }

        // 计算最大点数
        Optional<Integer> optional = seatDiceSum.keySet().stream().max(Comparator.naturalOrder());

        // 最大点数者为庄
        optional.ifPresent(max -> {
            Optional<? extends Player> playerOptional = players.stream()
                    .filter(p -> p.getPosition() == seatDiceSum.get(max)).findFirst();
            playerOptional.ifPresent(player -> player.setBanker(Boolean.TRUE));
        });
    }


    // ---------------------------------------------------------------- private

    /**
     * 是否给下一个玩家发牌
     *
     * @param player 玩家信息
     */
    private boolean drawTurn(Player player) {
        return !player.getHandsCards().isEmpty() && player.getHandsCards().size() % 4 == 0;
    }
}
